From 10f097660035cec88e5f385e7f01d2902d639a4d Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 23 Oct 2008 11:53:52 +0100 Subject: [PATCH] spinlock: Add debug-build checks for IRQ-safe spinlocks. Signed-off-by: Keir Fraser --- xen/arch/x86/setup.c | 2 ++ xen/common/spinlock.c | 52 ++++++++++++++++++++++++++++++++++++++ xen/include/xen/spinlock.h | 21 +++++++++++++-- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 967014e301..784a833aca 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1059,6 +1059,8 @@ void __init __start_xen(unsigned long mbi_p) cmdline) != 0) panic("Could not set up DOM0 guest OS\n"); + spin_debug_enable(); + /* Scrub RAM that is still free and so may go to an unprivileged domain. */ scrub_heap_pages(); diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c index 438e51deb8..95affbde01 100644 --- a/xen/common/spinlock.c +++ b/xen/common/spinlock.c @@ -1,9 +1,48 @@ #include +#include #include #include +#ifndef NDEBUG + +static atomic_t spin_debug __read_mostly = ATOMIC_INIT(0); + +static void check_lock(struct lock_debug *debug) +{ + int irq_safe = !local_irq_is_enabled(); + + if ( unlikely(atomic_read(&spin_debug) <= 0) ) + return; + + /* A few places take liberties with this. */ + /* BUG_ON(in_irq() && !irq_safe); */ + + if ( unlikely(debug->irq_safe != irq_safe) ) + { + int seen = cmpxchg(&debug->irq_safe, -1, irq_safe); + BUG_ON(seen == !irq_safe); + } +} + +void spin_debug_enable(void) +{ + atomic_inc(&spin_debug); +} + +void spin_debug_disable(void) +{ + atomic_dec(&spin_debug); +} + +#else /* defined(NDEBUG) */ + +#define check_lock(l) ((void)0) + +#endif + void _spin_lock(spinlock_t *lock) { + check_lock(&lock->debug); _raw_spin_lock(&lock->raw); } @@ -11,6 +50,7 @@ void _spin_lock_irq(spinlock_t *lock) { ASSERT(local_irq_is_enabled()); local_irq_disable(); + check_lock(&lock->debug); _raw_spin_lock(&lock->raw); } @@ -18,6 +58,7 @@ unsigned long _spin_lock_irqsave(spinlock_t *lock) { unsigned long flags; local_irq_save(flags); + check_lock(&lock->debug); _raw_spin_lock(&lock->raw); return flags; } @@ -41,16 +82,19 @@ void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) int _spin_is_locked(spinlock_t *lock) { + check_lock(&lock->debug); return _raw_spin_is_locked(&lock->raw); } int _spin_trylock(spinlock_t *lock) { + check_lock(&lock->debug); return _raw_spin_trylock(&lock->raw); } void _spin_barrier(spinlock_t *lock) { + check_lock(&lock->debug); do { mb(); } while ( _raw_spin_is_locked(&lock->raw) ); mb(); } @@ -70,6 +114,8 @@ void _spin_lock_recursive(spinlock_t *lock) /* Don't allow overflow of recurse_cpu field. */ BUILD_BUG_ON(NR_CPUS > 0xfffu); + check_lock(&lock->debug); + if ( likely(lock->recurse_cpu != cpu) ) { spin_lock(lock); @@ -92,6 +138,7 @@ void _spin_unlock_recursive(spinlock_t *lock) void _read_lock(rwlock_t *lock) { + check_lock(&lock->debug); _raw_read_lock(&lock->raw); } @@ -99,6 +146,7 @@ void _read_lock_irq(rwlock_t *lock) { ASSERT(local_irq_is_enabled()); local_irq_disable(); + check_lock(&lock->debug); _raw_read_lock(&lock->raw); } @@ -106,6 +154,7 @@ unsigned long _read_lock_irqsave(rwlock_t *lock) { unsigned long flags; local_irq_save(flags); + check_lock(&lock->debug); _raw_read_lock(&lock->raw); return flags; } @@ -129,6 +178,7 @@ void _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void _write_lock(rwlock_t *lock) { + check_lock(&lock->debug); _raw_write_lock(&lock->raw); } @@ -136,6 +186,7 @@ void _write_lock_irq(rwlock_t *lock) { ASSERT(local_irq_is_enabled()); local_irq_disable(); + check_lock(&lock->debug); _raw_write_lock(&lock->raw); } @@ -143,6 +194,7 @@ unsigned long _write_lock_irqsave(rwlock_t *lock) { unsigned long flags; local_irq_save(flags); + check_lock(&lock->debug); _raw_write_lock(&lock->raw); return flags; } diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index c49be63c5f..fec4264590 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -5,21 +5,38 @@ #include #include +#ifndef NDEBUG +struct lock_debug { + int irq_safe; /* +1: IRQ-safe; 0: not IRQ-safe; -1: don't know yet */ +}; +#define _LOCK_DEBUG { -1 } +void spin_debug_enable(void); +void spin_debug_disable(void); +#else +struct lock_debug { }; +#define _LOCK_DEBUG { } +#define spin_debug_enable() ((void)0) +#define spin_debug_disable() ((void)0) +#endif + typedef struct { raw_spinlock_t raw; u16 recurse_cpu:12; u16 recurse_cnt:4; + struct lock_debug debug; } spinlock_t; -#define SPIN_LOCK_UNLOCKED { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0 } + +#define SPIN_LOCK_UNLOCKED { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG } #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED) typedef struct { raw_rwlock_t raw; + struct lock_debug debug; } rwlock_t; -#define RW_LOCK_UNLOCKED { _RAW_RW_LOCK_UNLOCKED } +#define RW_LOCK_UNLOCKED { _RAW_RW_LOCK_UNLOCKED, _LOCK_DEBUG } #define DEFINE_RWLOCK(l) rwlock_t l = RW_LOCK_UNLOCKED #define rwlock_init(l) (*(l) = (rwlock_t)RW_LOCK_UNLOCKED) -- 2.30.2